﻿using Generic.App.Application.Contracts.Dto;
using Generic.App.Application.Contracts.Service;
using Generic.Domain.Shared.Result;
using Generic.Helper.Configure;
using Generic.Helper.Cryptography;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace Generic.App.HttpApi.Controllers
{
    public class AuthController : BaseApiController
    {
        private readonly IOptions<JwtOptions> _jwtOptions;
        private readonly IOptions<AesOptions> _aesOptions;
        private readonly IAppAccountService _appAccountService;
        public AuthController(IOptions<JwtOptions> jwtOptions, IOptions<AesOptions> aesOptions, IAppAccountService appAccountService)
        {
            _jwtOptions = jwtOptions;
            _aesOptions = aesOptions;
            _appAccountService = appAccountService;
        }

        [AllowAnonymous]
        [HttpPost]
        public async Task<CustomResult> Token(AppAccountLoginDto login)
        {
            login.AppSecret = login.AppSecret.AesEncypt(_aesOptions.Value.Key, _aesOptions.Value.IV);
            var sysUserDto = await _appAccountService.LoginAsync(login);
            var claimArr = new Claim[] {
                new Claim(ClaimTypes.Name,sysUserDto.AppId)
            };
            var result = new CustomResult(new
            {
                token = getJwtToken(claimArr),
                expires = _jwtOptions.Value.ExpiresMinute * 60
            });
            return result;
        }

        internal string getJwtToken(Claim[] claimArr)
        {
            int expires = _jwtOptions.Value.ExpiresMinute * 60;
            var claims = new List<Claim>
                {
                    new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") ,
                    new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddSeconds(expires)).ToUnixTimeSeconds()}")
                };
            foreach (var item in claimArr)
            {
                claims.AddLast(item);
            }
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtOptions.Value.Securitykey));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var token = new JwtSecurityToken(
                issuer: _jwtOptions.Value.Issuer,
                audience: _jwtOptions.Value.Audience,
                claims: claims,
                expires: DateTime.Now.AddSeconds(expires),
                signingCredentials: creds);
            return new JwtSecurityTokenHandler().WriteToken(token);
        }

        [HttpPost]
        public CustomResult TokenRefresh()
        {
            var expClaim = User.Claims.Where(c => c.Type == JwtRegisteredClaimNames.Exp).First();
            int minRefreshMinuteRemain = _jwtOptions.Value.MinRefreshMinuteRemain;
            var tokenExpired = Convert.ToInt32(expClaim.Value);
            if (tokenExpired < new DateTimeOffset(DateTime.Now.AddMinutes(minRefreshMinuteRemain)).ToUnixTimeSeconds())
            {
                var expires = _jwtOptions.Value.ExpiresMinute * 60;
                var userNameClaim = User.Claims.Where(c => c.Type == ClaimTypes.Name).First();
                var result = new CustomResult(new
                {
                    token = getJwtToken(new Claim[] { userNameClaim }),
                    expires = expires
                });
                return result;
            }
            else
            {
                var result = new CustomResult(new
                {
                    token = HttpContext.Request.Headers["Authorization"].ToString().Replace("Bearer ", "", StringComparison.OrdinalIgnoreCase),
                    expires = tokenExpired - new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()
                });
                return result;
            }
        }
    }
}
